package com.king.designpatterns.创造型模式.原型模式;

import java.util.Random;

/**
 * 原型模式（Prototype Pattern）是一种简单的设计模式。
 *
 * 定义：用原型实例指定创建对象的种类，并且通过复制这些原型创建新的对象。
 *
 * 角色：
 *      ■ 客户（Client）角色：
 *          该角色提出创建对象的请求。
 *      ■ 抽象原型（Prototype）角色：
 *          该角色是一个抽象角色，通常由一个Java接口或抽象类实现，给出所有的具体原型类所需的接口。
 *      ■ 具体原型（Concrete Prototype）角色：
 *          该角色是被复制的对象，必须实现抽象原型接口。
 *
 * 优点：
 *      ■ 性能优良：原型模式是在内存二进制流的复制，要比直接new一个对象性能好，特别是在一个循环体内产生大量的对象时，原型模式可以更好地体现其优点。
 *      ■ 逃避构造函数的约束：这既是优点也是缺点，直接在内存中复制，构造函数是不会执行的，因此减少了约束，需要在实际应用时进行权衡考虑。
 *
 * 场景：
 *      ■ 资源优化场景，类初始化需要消化非常多的资源，这个资源包括数据、硬件资源等。
 *      ■ 性能和安全要求的场景，通过new产生一个对象需要非常烦琐的数据准备或访问权限，可以使用原型模式。
 *      ■ 一个对象多个修改者的场景，一个对象需要提供给其他对象访问，而且各个调用者可能都需要修改其值时，可以考虑使用原型模式复制多个对象供调用者使用。
 *
 * @author king
 * @date 2021-06-07 17:45
 */
public class PrototypePattern {
    // 发送账号的数量
    private static int MAX_COUNT = 6;
    private static Random random = new Random();

    public static void main(String[] args) {
        // 模拟发送邮件
        int i = 0;
        // 定义一个邮件对象
        Mail mail = new Mail("某商场五一抽奖获得", "五一抽奖获得通知：~~~~~~~");
        mail.setTail("解释权归商场所有");

        while(i < MAX_COUNT){
            // 克隆邮件
            Mail clone = mail.clone();
            // 以下是每封邮件不同的地方
            clone.setAppellation(getRandString(5) + " 先生（女士）");
            clone.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");
            sendMail(clone);
            ++i;
        }
    }

    /**
     * 发送邮件
     * @param mail mail
     */
    public static void sendMail(Mail mail){
        System.out.println("标题：" + mail.getSubject() + "\t收件人：" + mail.getReceiver() + "\t...发送成功！");
    }

    /**
     * 获取指定长度的随机字符串
     * @param maxLength 长度
     * @return String
     */
    public static String getRandString(int maxLength) {
        String source = "abcdefghijklmnopqrstuvwxyzABCEDFGHIJKLMNOPQRSTUVWXYZ";

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < maxLength; i++) {
            sb.append(source.charAt(random.nextInt(source.length())));
        }
        return sb.toString();
    }
}
